package cn.springmvc.noconfig.config;

import cn.springmvc.noconfig.converter.MyConverter;
import cn.springmvc.noconfig.converter.MyFormatter;
import cn.springmvc.noconfig.converter.MyMessageConverter;
import cn.springmvc.noconfig.converter.MyMethodArgumentsResolver;
import cn.springmvc.noconfig.interceptor.TestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.accept.PathExtensionContentNegotiationStrategy;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.servlet.view.ContentNegotiatingViewResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
import org.springframework.web.servlet.view.freemarker.FreeMarkerView;
import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;

import java.util.*;

/**
 * ClassName: MvcConfig
 * Desc:  代替SpringMVC的配置文件，可以实现 WebMvcConfigurer 也可以继承 WebMvcConfigurerAdapter
 * Date： 2017/5/3
 * Created：shaom
 */
@Configuration
@EnableWebMvc
@EnableScheduling
@ComponentScan(basePackages = "cn.springmvc.noconfig")
public class MvcConfig extends WebMvcConfigurerAdapter {

    /**
     * 简单视图跳转
     *
     * @param registry
     */
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/test").setViewName("test");
    }

    /**
     * 自定义JSP的视图
     *
     * @return
     */
    @Bean
    public InternalResourceViewResolver jspViewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/pages/");
        viewResolver.setSuffix(".jsp");
//        viewResolver.setViewClass(JstlView.class);
        viewResolver.setRequestContextAttribute("ctx");
        return viewResolver;
    }

    /**
     * 自定义 FreeMarker 视图
     *
     * @return
     */
    @Bean
    public FreeMarkerViewResolver freeMarkerViewResolver() {
        FreeMarkerViewResolver viewResolver = new FreeMarkerViewResolver();
        viewResolver.setCache(true);
        viewResolver.setPrefix("/WEB-INF/pages/");
        viewResolver.setSuffix(".ftl");
        viewResolver.setRequestContextAttribute("ctx");
        return viewResolver;
    }

    /**
     * 视图配置 View
     *
     * @param registry
     */
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.viewResolver(jspViewResolver());
        registry.viewResolver(freeMarkerViewResolver());
    }

    /**
     * Resource 静态资源配置
     *
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resource/**").addResourceLocations("/resource/");
    }

    /**
     * Interceptors 配置拦截器
     *
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(handlerInterceptor()).addPathPatterns("/**").excludePathPatterns("/resource/**");
    }

    /**
     * 自定义拦截器
     *
     * @return
     */
    @Bean
    public HandlerInterceptor handlerInterceptor() {
        TestInterceptor testInterceptor = new TestInterceptor();
        return testInterceptor;
    }

    /**
     * UpLoad 上传配置
     *
     * @return
     */
    @Bean
    public MultipartResolver multipartResolver() {
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
        multipartResolver.setDefaultEncoding("UTF-8");
        multipartResolver.setMaxUploadSize(1024 * 1024);
        multipartResolver.setMaxInMemorySize(1024 * 4);
        return multipartResolver;
    }

    /**
     * HttpMessageConverter：处理request 和 response 里的数据转换
     * configureMessageConverters: 会覆盖spring默认的 HttpMessageConverter
     * extendMessageConverters: 仅仅添加一个自定义的HttpMessageConverter，不会覆盖
     *
     * @param converters
     */
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(messageConverter());
    }

    /**
     * 自定义的 HttpMessageConverter
     *
     * @return
     */
    @Bean
    public HttpMessageConverter messageConverter() {
        return new MyMessageConverter();
    }

    /**
     * 配置动态视图处理(多种输出格式)，可以根据访问后缀实现不同的输出
     * http://www.yiibai.com/spring_mvc/spring-4-mvc-contentnegotiatingviewresolver-example.html
     * 配置 ContentNegotiationManager ， ContentNegotiationConfigurer 就是配置 ContentNegotiationManager的
     *
     * @param configurer
     */
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {

//        configurer.ignoreAcceptHeader(true).defaultContentType(MediaType.TEXT_HTML);

        //或者配置 Strategy
        Map<String, MediaType> mediaTypes = new HashMap<>();
        mediaTypes.put("json", MediaType.APPLICATION_JSON);
        mediaTypes.put("html", MediaType.TEXT_HTML);
        mediaTypes.put("xml", MediaType.APPLICATION_XML);
        mediaTypes.put("atom", MediaType.APPLICATION_ATOM_XML);
        PathExtensionContentNegotiationStrategy strategy = new PathExtensionContentNegotiationStrategy(mediaTypes);
        configurer.defaultContentTypeStrategy(strategy);
    }

    /**
     * 多视图解析器
     *
     * @param manager
     * @return
     */
    @Bean
    public ViewResolver contentNegotiatingViewResolver(ContentNegotiationManager manager) {
        ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
        resolver.setContentNegotiationManager(manager);

        // Define all possible view resolvers
        List<ViewResolver> resolvers = new ArrayList<>();

        // 添加各种视图解析器 实现 ViewResolver 接口
        resolvers.add(jspViewResolver());

        // 默认视图
        resolver.setDefaultViews(Collections.singletonList(new MappingJackson2JsonView()));//spring提供的json
        resolver.setViewResolvers(resolvers);
        return resolver;
    }


    /**
     * 配置参数解析器（用于接收参数）
     *
     * @param argumentResolvers
     */
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(argumentResolver());
    }

    /**
     * 自定义的参数解析器
     *
     * @return
     */
    @Bean
    public HandlerMethodArgumentResolver argumentResolver() {
        return new MyMethodArgumentsResolver();
    }


    /**
     * 配置格式化工具（用于接收参数）
     *
     * @param registry
     */
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addFormatter(formatter());
        registry.addConverter(converter());
    }

    @Bean
    public MyFormatter formatter() {
        return new MyFormatter();
    }

    @Bean
    public MyConverter converter() {
        return new MyConverter();
    }
}
